#include "header.h"

void *connectJoin(void *ptr)														//CONNECT TO ALL OTHER BEACON NODE
{
	//printf("CONNECTJOIN THREAD CREATED\n");
	pthread_t readThread;															// Read thread to receive the data coming from each node
	pthread_t writeThread;															// write therad to send the data going to each node
	
	char hostName[100];
	memset(hostName,'\0',100*sizeof(char));
	uint16_t Port;
	char *hostnamePort = (char *) ptr;
	////printf("Inside Connect Beacon Name and Port = %s\n",hostnamePort);
	sscanf(hostnamePort, "%s %hu",hostName, &Port);								
	hostName[strlen(hostName)+1] = '\0';
	//printf("Host Name inside ConnectJoin is %s\n",hostName);
	//printf("Port inside ConnectJoin is %hu\n",Port);

	int joinSock;
	int conClient; 
	struct hostent *he;
	struct sockaddr_in serverAddress;



	joinSock = socket(AF_INET,SOCK_STREAM,0);									//create socket and connect
	if (joinSock == -1)
	{
		perror("Create socket\n");
	}
	////printf("Socket Created\n");

	memset(&he,0,sizeof(he));
	he = gethostbyname(hostName);
	memset(&serverAddress,'\0',sizeof(serverAddress));
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)he->h_addr_list[0]));
	serverAddress.sin_port = htons(Port);

	conClient = connect(joinSock, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr));
	if(conClient<0)
	{
		perror("Not able to Connect in ConnectJoin and EXITING\n");
		pthread_exit(NULL);
	}


																								//SEND HELLO HEADER
	unsigned int dataLength = (uint32_t)(sizeof(uint16_t)+ strlen(node.getHostName()));				// data length for hello
	Header sendHeader = createHeader((uint8_t)helloMessageType, dataLength);
	
	
	//printf("Type = 0x%02x\n",sendHeader.messageType);
	//printUOID(sendHeader.uoid);
	////printf("TTL = %hhu\n",sendHeader.ttl);
	////printf("Reserved = %hhu\n",sendHeader.reserved);
	////printf("Datalength = %u\n",sendHeader.dataLength);
	
	char sendheaderBuffer[28];
	memset(sendheaderBuffer,'\0',28);
	memcpy(&sendheaderBuffer[0],&htons(sendHeader.messageType),1);
	memcpy(&sendheaderBuffer[1],sendHeader.uoid,20);
	memcpy(&sendheaderBuffer[21],&htons(sendHeader.ttl),1);
	memcpy(&sendheaderBuffer[22],&htons(sendHeader.reserved),1);
	memcpy(&sendheaderBuffer[23],&htonl(sendHeader.dataLength),4);
	sendheaderBuffer[strlen(sendheaderBuffer)+1] = '\0';
	int sendHeaderBytes = send(joinSock,&sendheaderBuffer,27,0);	
	if(sendHeaderBytes != 27)
	{
		//printf("Header was not completely sent in CONNECT JOIN\n");
		pthread_exit(NULL);
	}
	printf("Header Sent\n");

																				// SEND HELLO MESSAGE
	HelloMessage helloMsg = sendHello();
	////printf("port = %hu\n",helloMsg.port);

	char sendMessageBuffer[sendHeader.dataLength+1];
	////printf(" HostName ---->%s---\n",helloMsg.hostname);
	memset(sendMessageBuffer,'\0',(sendHeader.dataLength+1)*sizeof(char));
	memcpy(&sendMessageBuffer[0],&htons(helloMsg.port),2);
	memcpy(&sendMessageBuffer[2],(char *)helloMsg.hostname,strlen(helloMsg.hostname));
	sendMessageBuffer[strlen(sendMessageBuffer)+1] = '\0';
	printf("Sent Message is : %s---\n",sendMessageBuffer);
	int sendMsgBytes = send(joinSock,&sendMessageBuffer,sendHeader.dataLength,0);																				
	if(sendMsgBytes != (int) sendHeader.dataLength)
	{
		//printf("Msg was not completely sent in CONNECT JOIN\n");
		pthread_exit(NULL);
	}
	////printf("send bytes = %d\n",sendHelloMessage);
	
		
	Messages msg1;
    msg1.Header = (char *)malloc(28*sizeof(char));
    memset(msg1.Header,'\0',28);
    msg1.Data = (char *)malloc(512*sizeof(char));
    memset(msg1.Data,'\0',512);
    memcpy(&msg1.Header[0],&sendMessageBuffer[0],27);
    memcpy(&msg1.Data[0],&helloMsg.port,2);
    memcpy(&msg1.Data[2],&helloMsg.hostname[0],13);
    struct timeval t1;
    gettimeofday(&t1, NULL);
    enterLogMessage(msg1,'s',t1);



	struct timeval selectTimeOut;
	selectTimeOut.tv_sec = 1;
	selectTimeOut.tv_usec = 0; 
	


	fd_set readfds;
	
			
	int rv;
	struct timeval keepAliveTimeOutFirst, keepAliveTimeOutLast;
	gettimeofday(&keepAliveTimeOutFirst, NULL);

	while(1)
	{
		if(shutdownFlag == true)
		{
			//printf("ConnectJoin Thread exit due to Shutdown\n");
			pthread_exit(NULL);
		}
		gettimeofday(&keepAliveTimeOutLast, NULL);

		FD_ZERO(&readfds);
		FD_SET(joinSock, &readfds);	
				
		if ((uint32_t)(keepAliveTimeOutLast.tv_sec - keepAliveTimeOutFirst.tv_sec) >= node.getKeepAliveTimeout()) 
		{
			//printf("Keep Alive timeout took place in CONNECT JOIN and EXITING\n");
			pthread_exit(NULL);
		}

		rv = select(joinSock+1, &readfds, NULL, NULL, &selectTimeOut);

		if (rv == -1) 
		{
			perror("select 2\n"); // error occurred in select()
			close(joinSock);
			pthread_exit(NULL);
		}
		else if(rv == 0)
		{
			continue;
		}               
		else if(rv > 0)
		{
			break;
		}
	}

	Header recHeader;																			// RECEIVE HELLO HEADER
	
	char recHeaderBuffer[28];
	memset(recHeaderBuffer,'\0',28);
	int recHeaderBytes = recv(joinSock,&recHeaderBuffer,27,0);
	if(recHeaderBytes != 27)
	{
		//printf("Header was not completely received in CONNECT JOIN\n");
		pthread_exit(NULL);
	}
	recHeaderBuffer[strlen(recHeaderBuffer)+1] = '\0';
	printf("Header Received\n");

	recHeader.uoid = (unsigned char *)malloc(20* sizeof(char));
	memcpy(&recHeader.messageType,&ntohs(recHeaderBuffer[0]),1);
	memcpy(recHeader.uoid,&recHeaderBuffer[1],20);
	memcpy(&recHeader.ttl,&ntohs(recHeaderBuffer[21]),1);
	memcpy(&recHeader.reserved,&ntohs(recHeaderBuffer[22]),1);
	memcpy(&recHeader.dataLength,&ntohl(recHeaderBuffer[23]),4);
		
		
	//printf("Type = 0x%02x\n",recHeader.messageType);
	//printUOID(recHeader.uoid);
	////printf("TTL = %hhu\n",recHeader.ttl);
	////printf("Reserved = %hhu\n",recHeader.reserved);
	////printf("Datalength = %u\n",recHeader.dataLength);
																		
	HelloMessage recHello;																		//RECEIVE HELLO MESSAGE
	char recMessageBuffer[recHeader.dataLength+1];
	memset(recMessageBuffer,'\0',(recHeader.dataLength+1)*sizeof(char));
	int recMsgBytes = recv(joinSock,&recMessageBuffer,recHeader.dataLength,0);	
	if(recMsgBytes != (int)recHeader.dataLength)
	{
		//printf("Msg was not completely received in CONNECT JOIN\n");
		pthread_exit(NULL);
	}
	recMessageBuffer[strlen(recMessageBuffer)+1] = '\0';
	printf("Message Received = %s\n",recMessageBuffer);
		

	recHello.hostname = (char *)malloc(100 * sizeof(char));
	//bzero(recHello.hostname,100 *sizeof(char));
	//char* buffer=new char[100]; delete[] buffer;
	memset(recHello.hostname,'\0',100 *sizeof(char));
	memcpy(&recHello.port,&ntohs(recMessageBuffer[0]),2);
	memcpy(recHello.hostname,&recMessageBuffer[2],recHeader.dataLength-2);
	recHello.hostname[strlen(recHello.hostname)+1] = '\0';
	
	//printf("Received Hello Host name = %s\n",recHello.hostname);
	//printf("Received Hello Port = %hu\n",recHello.port);

	Messages msg;
    msg.Header = (char *)malloc(28*sizeof(char));
    memset(msg.Header,'\0',28);
    msg.Data = (char *)malloc(512*sizeof(char));
    memset(msg.Data,'\0',512);
    memcpy(&msg.Header[0],&recHeaderBuffer[0],27);
    memcpy(&msg.Data[0],&recHello.port,2);
    memcpy(&msg.Data[2],&recHello.hostname[0],13);
    struct timeval t;
    gettimeofday(&t, NULL);
    enterLogMessage(msg,'r',t);

	char hostNamePort[100];
	memset(hostNamePort,'\0',100*sizeof(char));
	sprintf(hostNamePort,"%s:%u",recHello.hostname,recHello.port);										//concat senders host name and port by :
		
	
	pthread_mutex_lock(&NeighborList);																//Apply LOCK

	multimap<string,int> tempMap = node.getNeighborList();
	tempMap.insert(pair<string,int>(hostNamePort,joinSock));								//add to
	node.setNeighborList(tempMap);
	////printf("Size of neighbor list is %d\n",node.getNeighborList().size());

	pthread_mutex_unlock(&NeighborList);															//Release LOCK


	deleteConnection[joinSock] = false;

	iretReadThread = pthread_create(&readThread, NULL, read, (void *) joinSock);
	iretWriteThread = pthread_create(&writeThread, NULL, write, (void *)joinSock);
	iretKeepAliveThread = pthread_create(&keepAliveThread, NULL, keepAlive, (void *)joinSock);


	//pthread_join( readThread, NULL);
	//pthread_join( writeThread, NULL);

	return NULL;
}
